package org.iabako.server.dao.user;

import org.iabako.server.dao.JpaDAO;
import org.iabako.server.tools.ServerTools;
import org.iabako.shared.entity.user.Enterprise;
import org.iabako.shared.entity.user.EnterpriseBalance;
import org.iabako.shared.entity.user.EnterpriseTrack;
import org.iabako.shared.entity.user.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.*;

/**
 * Created by jose on 24/09/14.
 */

@Repository("userDAO")
public class UserDAO extends JpaDAO<Long, User> {

    @Autowired
    EnterpriseDAO enterpriseDAO;

    @Override
    protected String getUniqueNumberVerificationQuery() {
        return null;
    }

    @Override
    protected String getLastNumberQuery() {
        return null;
    }

    public User getUserByEmail(String email) {
        String query = "SELECT user FROM User user WHERE user.email = :email AND user.active = 1";
        List<User> users = entityManager.createQuery(query).setParameter("email", email).getResultList();
        return users == null || users.isEmpty() ? null : users.get(0);
    }

    /**
     * This method is used by email verification service (user is not active yet)
     *
     * @param email
     * @return
     */
    public User getDisableUserByEmail(String email) {
        String query = "SELECT user FROM User user WHERE user.email = :email AND user.active = 0";
        List<User> users = entityManager.createQuery(query).setParameter("email", email).getResultList();
        //If more than one, we return the last one
        return users == null || users.isEmpty() ? null : users.get(users.size() - 1);
    }

    public List<EnterpriseTrack> getEnterpriseTracks(EnterpriseBalance enterpriseBalance) {
        String query = "SELECT track FROM EnterpriseTrack track WHERE track.enterpriseBalance = :enterpriseBalance";
        return entityManager.createQuery(query).setParameter("enterpriseBalance", enterpriseBalance).getResultList();
    }

    public void deleteNoActiveUsersWithSameEmail(String email) {
        String query = "UPDATE User user SET user.userPayPalToken = NULL WHERE user.email = :email AND user.active = 0";
        entityManager.createQuery(query).setParameter("email", email).executeUpdate();

        query = "DELETE FROM UserPayPalToken upt WHERE upt.payer.id IN (SELECT user.id FROM User user WHERE user.email = :email AND user.active = 0)";
        entityManager.createQuery(query).setParameter("email", email).executeUpdate();

        query = "DELETE FROM User user WHERE user.email = :email AND user.active = 0";
        entityManager.createQuery(query).setParameter("email", email).executeUpdate();
    }

    public List<User> getUsersByEnterprise(Enterprise enterprise) {
        String query = "SELECT user FROM User user WHERE user.enterprise IN (:enterprises) AND user.active = 1";
        return entityManager.createQuery(query).setParameter("enterprises", enterprise.getAllRelatedEnterprises()).getResultList();
    }

    public List<User> getUsersByPayPalToken(String transactionId) {
        String query = "SELECT user FROM User user WHERE user.userPayPalToken.transactionId = :transactionId";
        return entityManager.createQuery(query).setParameter("transactionId", transactionId).getResultList();
    }

    public Enterprise getEnterpriseByUserEmail(String userEmail) {
        String query = "SELECT enterprise FROM Enterprise enterprise WHERE enterprise = " +
                "(SELECT user.enterprise FROM User user WHERE user.email = :email AND user.active = 1)";
        return (Enterprise) entityManager.createQuery(query).setParameter("email", userEmail).getSingleResult();
    }

    public void deleteDemoData() {
        String query = "DELETE FROM Expense expense WHERE expense.enterprise IN (SELECT e FROM Enterprise e WHERE e.demo = 1)";
        entityManager.createQuery(query).executeUpdate();

        query = "DELETE FROM Installment installment WHERE installment.sale IN (SELECT sale FROM Sale sale WHERE sale.enterprise " +
                "IN (SELECT e FROM Enterprise e WHERE e.demo = 1))";
        entityManager.createQuery(query).executeUpdate();

        query = "DELETE FROM Payment payment WHERE payment.sale IN (SELECT sale FROM Sale sale WHERE sale.enterprise " +
                "IN (SELECT e FROM Enterprise e WHERE e.demo = 1))";
        entityManager.createQuery(query).executeUpdate();

        query = "DELETE FROM SaleProductService productsServices WHERE productsServices.sale IN (SELECT sale FROM Sale sale WHERE sale.enterprise " +
                "IN (SELECT e FROM Enterprise e WHERE e.demo = 1))";
        entityManager.createQuery(query).executeUpdate();

        //delete orphan sales
        query = "DELETE FROM Sale sale WHERE sale NOT IN (SELECT DISTINCT productsServices.sale FROM SaleProductService productsServices) ";
        entityManager.createQuery(query).executeUpdate();

        query = "DELETE FROM Service service WHERE service.enterprise IN (SELECT e FROM Enterprise e WHERE e.demo = 1)";
        entityManager.createQuery(query).executeUpdate();

        query = "DELETE FROM Product product WHERE product.enterprise IN (SELECT e FROM Enterprise e WHERE e.demo = 1)";
        entityManager.createQuery(query).executeUpdate();

        query = "DELETE FROM Client client WHERE client.enterprise IN (SELECT e FROM Enterprise e WHERE e.demo = 1)";
        entityManager.createQuery(query).executeUpdate();

        query = "DELETE FROM User user WHERE user.enterprise IN (SELECT e FROM Enterprise e WHERE e.demo = 1)";
        entityManager.createQuery(query).executeUpdate();

        query = "DELETE FROM Enterprise e WHERE e.demo = 1";
        entityManager.createQuery(query).executeUpdate();
    }

    public List<User> getDemoUserCreatedOn(Date date) {
        ServerTools serverTools = new ServerTools();
        date = serverTools.resetTime((Date) date.clone());
        Date datePlusOne = serverTools.addDaysToDate((Date) date.clone(), 1);

        String query = "SELECT u FROM User u JOIN u.enterprise e " +
                "WHERE e.demo = 1 AND u.creationDate >= :date AND u.creationDate < :datePlusOne";

        return entityManager.createQuery(query).setParameter("date", date).setParameter("datePlusOne", datePlusOne).getResultList();
    }

    public List<User> getLoggedUsersOn(Date date) {
        ServerTools serverTools = new ServerTools();
        date = serverTools.resetTime((Date) date.clone());
        Date datePlusOne = serverTools.addDaysToDate((Date) date.clone(), 1);

        String query = "SELECT u FROM User u " +
                "WHERE u.lastLogin >= :date AND u.lastLogin < :datePlusOne";

        return entityManager.createQuery(query).setParameter("date", date).setParameter("datePlusOne", datePlusOne).getResultList();
    }

    public Map<Enterprise, List<User>> getMultiUsersEnterprises() {
        String query = "SELECT u FROM User u JOIN u.enterprise e " +
                "WHERE e.demo = 0 " +
                "AND size(e.users) > 1 " +
                "OR e IN (SELECT child.parentEnterprise FROM Enterprise child WHERE child.parentEnterprise IS NOT NULL AND child.users IS NOT EMPTY)";
        List<User> users = entityManager.createQuery(query).getResultList();

        Map<Enterprise, List<User>> enterpriseMap = new HashMap<Enterprise, List<User>>();

        //Add parent users to Map
        for (User user : users) {
            if (enterpriseMap.get(user.getEnterprise()) == null) {
                enterpriseMap.put(user.getEnterprise(), new ArrayList<User>());
            }
            enterpriseMap.get(user.getEnterprise()).add(user);
        }

        //Add children users to Map
        for (Enterprise e : enterpriseMap.keySet()) {
            List<Enterprise> children = enterpriseDAO.getChildrenEnterprises(e);

            for (Enterprise child : children) {
                enterpriseMap.get(e).addAll(child.getUsers());
            }
        }

        return enterpriseMap;
    }

    public void detachRelatedObjects(Long id) {
        String query = "UPDATE Client c SET c.lastModificationUser = NULL where c.lastModificationUser.id = :id";
        entityManager.createQuery(query).setParameter("id", id).executeUpdate();

        query = "UPDATE Product p SET p.lastModificationUser = NULL where p.lastModificationUser.id = :id";
        entityManager.createQuery(query).setParameter("id", id).executeUpdate();

        query = "UPDATE Service s SET s.lastModificationUser = NULL where s.lastModificationUser.id = :id";
        entityManager.createQuery(query).setParameter("id", id).executeUpdate();

        query = "UPDATE Sale s SET s.lastModificationUser = NULL where s.lastModificationUser.id = :id";
        entityManager.createQuery(query).setParameter("id", id).executeUpdate();

        query = "UPDATE Expense e SET e.lastModificationUser = NULL where e.lastModificationUser.id = :id";
        entityManager.createQuery(query).setParameter("id", id).executeUpdate();

        query = "DELETE FROM TrackingObject to WHERE to.tracking IN (SELECT t FROM Tracking t WHERE t.user.id = :id)";
        entityManager.createQuery(query).setParameter("id", id).executeUpdate();

        query = "DELETE FROM Tracking t WHERE t.user.id = :id";
        entityManager.createQuery(query).setParameter("id", id).executeUpdate();
    }
}
